package cn.jhz.learn.community_dynamic.security.provider;

import cn.jhz.learn.community_dynamic.security.manager.JwtManager;
import cn.jhz.learn.community_dynamic.security.model.JwtAuthenticationToken;
import cn.jhz.learn.community_dynamic.security.service.JsonUserDetailsService;

import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.MalformedClaimException;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwx.JsonWebStructure;
import org.jose4j.lang.JoseException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.www.NonceExpiredException;
import org.springframework.stereotype.Component;

@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {
    private final JsonUserDetailsService userService;
    private final JwtManager jwtManager;

    @Autowired
    public JwtAuthenticationProvider(JwtManager manager, JsonUserDetailsService userService) {
	this.jwtManager = manager;
        this.userService = userService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String jwt = (String) authentication.getCredentials();
        JwtClaims claims;
        UserDetails user;
        
        try {
	    JsonWebStructure structure = JsonWebSignature.fromCompactSerialization(jwt);
	    claims = jwtManager.validate(
		    jwt, jwtManager.rsaJsonWebKey(
			    null, structure.getKeyIdHeaderValue()).orElseThrow(()->new UsernameNotFoundException("Error Token")));
	    
	    user = userService.loadUserByUsername(claims.getSubject());
	    
	    if (user == null || user.getPassword() == null)
                throw new NonceExpiredException("Token expires");
	    
            //TODO 添加其他状态码的校验
	} catch (JoseException e) {
	    throw new UsernameNotFoundException("Error Token", e); 
	} catch (InvalidJwtException e) {
	    System.out.println(e);
	    // TODO 其他令牌错误
	    if (e.hasExpired()) { // JWT是否已经过期是失效的一个常见原因
                throw new NonceExpiredException("Token expires", e);
            }else{
                throw new UsernameNotFoundException("Error Token", e);
            }
	    
	} catch (MalformedClaimException e) {
	    // TODO Auto-generated catch block
	    throw new UsernameNotFoundException("Error Token", e);
	}
       

        //成功后返回认证信息，filter会将认证信息放入SecurityContext
        return new JwtAuthenticationToken(user, claims, user.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.isAssignableFrom(JwtAuthenticationToken.class);
    }
}
